/***************************************************************************************************
 *Copyright(C),2010-2016,Sumscope
 *FileName	:  DictThreadGuard.cpp
 *Author	:  scofined.qi
 *Version	:  1.0
 *Date		:  2019/06/14
 *Desc		:  //用于主要说明此程序文件完成的主要功能
 *Relation :
 *Others	:  //其他内容说明
 *Function :  //主要函数列表，每条记录应包含函数名及功能简要说明
 *History	:
 * //修改历史记录列表，每条修改记录应包含修改日期、修改者及修改内容简介
 ***************************************************************************************************/
#include "DictThreadGuard.h"

#include <core/time/time.h>

#include "DictUpdateManager.h"

#ifdef WIN32
#else
#include <pthread.h>
#include <signal.h>
#endif

#ifndef BLOGDEBUG
#define BLOGDEBUG  //
#endif
#ifndef BLOGERR
#define BLOGERR  //
#endif
#ifndef BLOGINFO
#define BLOGINFO  //
#endif
#ifndef BLOGCRIT
#define BLOGCRIT  //
#endif
#ifndef LOGWARN
#define LOGWARN  //
#endif
#ifndef LOGDEBUG
#define LOGDEBUG  //
#endif
#ifndef BLOGWARN
#define BLOGWARN  //
#endif
#ifndef LOGERR
#define LOGERR  //
#endif
#ifndef LOGINFO
#define LOGINFO  //
#endif
#ifndef LOGEMERG
#define LOGEMERG  //
#endif

#define BOOLTEST(kProfileDictRecreateOnError) true

DictThreadGuard::DictThreadGuard()
    : m_close_type(kThreadCloseRuning),
#ifdef CCORE_MAC
      m_thread_id(NULL),
#else
      m_thread_id(-1),
#endif
      m_start_count(0),
      m_exiting(false),
      m_last_tick(qb::base::GetHighResTime()),
      m_timeout_count(0) {
#ifdef WIN32
  _beginthread(DictThreadGuard::StaticRun, 0, 0);
#else
  pthread_t ntid;
  pthread_create(&ntid, NULL, StaticRun, NULL);
#endif
}

const char* DictThreadGuard::GetThreadCloseName(kThreadClose type) {
  static const char* names[kThreadCloseCount + 1] = {
      "Running", "Normal", "Killed", "DeadLoop", "Exception", "Unknown"};

  if (type < 0 || type >= kThreadCloseCount) return names[kThreadCloseCount];
  return names[type];
}

void DictThreadGuard::StopCheck() { m_exiting = true; }

void DictThreadGuard::RunCheck() {
  void* hThread = NULL;
  BLOGINFO("[DICT][GUARD]开始监控字典线程");
  for (; !m_exiting;) {
#ifdef WIN32
    Sleep(1000);
    DWORD tid = GetThreadId();
    if (hThread == NULL && tid != 0) {
      hThread = OpenThread(SYNCHRONIZE, false, tid);
      if (hThread != NULL) {
        BLOGINFO("[DICT][GUARD]成功打开字典线程句柄%d", tid);
      }
    }

    if (hThread == NULL) continue;
    if (WaitForSingleObject(hThread, 1000) == WAIT_OBJECT_0) {
      CloseHandle(hThread);
      hThread = NULL;
      BLOGINFO("[DICT][GUARD]字典线程[%8d]已经退出,可能原因", tid,
               GetThreadCloseName(m_close_type));
      if (m_close_type != kThreadCloseNormal) {
        if (false) DictUpdateManager::instance().StartDictThread(true);
      }
    }

    if (hThread != NULL && tid != 0) {
      CheckDeadLoop();
    }
#else
    sleep(1);
    pthread_t tid = GetThreadId();

#ifdef CCORE_MAC
    if (tid == NULL)
#else
    if (tid == -1)
#endif
      continue;

    int pthread_kill_err;
    pthread_kill_err = pthread_kill(tid, 0);

    if (pthread_kill_err == ESRCH) {
      BLOGINFO("[DICT][GUARD]字典线程[%8d]已经退出,可能原因", tid,
               GetThreadCloseName(m_close_type));
      if (m_close_type != kThreadCloseNormal) {
        if (false) DictUpdateManager::instance().StartDictThread(true);
      }
    }

#ifdef CCORE_MAC
    if (tid != NULL)
#else
    if (tid != -1)
#endif
    {
      CheckDeadLoop();
    }
#endif
  }
  BLOGINFO("[DICT][GUARD]结束监控字典线程[%8d]", m_thread_id);
}

#ifdef WIN32
void DictThreadGuard::StaticRun(void*)
#else
void* DictThreadGuard::StaticRun(void*)
#endif
{
  DictThreadGuard::Get().RunCheck();
#ifndef _MSC_VER
  return nullptr;
#endif
}

void DictThreadGuard::OnStart() {
#ifdef WIN32
  SetThreadId(GetCurrentThreadId());
#else
  SetThreadId(pthread_self());
#endif
}

void DictThreadGuard::OnEnd() {
  SCOPED_LOCK(m_lock);
  m_close_type = kThreadCloseNormal;
  BLOGINFO("[DICT]字典线程[%8d]正常退出", GetThreadId());
}

void DictThreadGuard::OnException() {
  SCOPED_LOCK(m_lock);
  m_close_type = kThreadCloseException;
}

void DictThreadGuard::OnHeartbeat(DWORD now) {
  SCOPED_LOCK(m_lock);
  DWORD last = m_last_tick;
  m_last_tick = now;
  if (now >= last + HARTBEAT_MAX) {
    m_timeout_count++;
    BLOGWARN("[DICT][GUARD]字典线程[%8d]已经触发第%2d次心跳超时,%2d为最大极限",
             GetThreadId(), m_timeout_count, TIMEOUT_MAX);
  } else {
    if (m_timeout_count > 0) {
      BLOGWARN(
          "[DICT][GUARD]字典线程[%8d]已经触发第%2d次心跳超时,现在已经恢复正常",
          GetThreadId(), m_timeout_count);
    }
    m_timeout_count = 0;
  }
}

void DictThreadGuard::CheckDeadLoop() {
  SCOPED_LOCK(m_lock);
  if (m_timeout_count > TIMEOUT_MAX) {
    BASSERT(0);
  }
}

#ifdef WIN32
DWORD DictThreadGuard::GetThreadId() {
  SCOPED_LOCK(m_lock);
  return m_thread_id;
}

void DictThreadGuard::SetThreadId(DWORD tid) {
  SCOPED_LOCK(m_lock);
  m_thread_id = tid;
  m_start_count++;
  BLOGINFO("[DICT][GUARD]第%2d次启动字典线程,id:%d", m_start_count, tid);
}
#else
pthread_t DictThreadGuard::GetThreadId() {
  SCOPED_LOCK(m_lock);
  return m_thread_id;
}

void DictThreadGuard::SetThreadId(pthread_t tid) {
  SCOPED_LOCK(m_lock);
  m_thread_id = tid;
  m_start_count++;
  BLOGINFO("[DICT][GUARD]第%2d次启动字典线程,id:%d", m_start_count, tid);
}
#endif
